package cn.lm.activit.module.multi.instance.cmd;

import org.activiti.bpmn.model.Activity;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.MultiInstanceLoopCharacteristics;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.history.HistoryManager;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.deploy.DeploymentManager;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.util.Activiti5Util;
import org.activiti.engine.impl.util.ProcessDefinitionUtil;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.Map;

/**
 * @author lm_jcf
 * @date 2019/5/20 16:36
 */
// 加签
public class AddMultiInstanceExecutionCmd implements Command<Void>, Serializable {

    protected final String NUMBER_OF_INSTANCES = "nrOfInstances";
    protected final String NUMBER_OF_ACTIVE_INSTANCES = "nrOfActiveInstances";
    protected final String NUMBER_OF_COMPLETED_INSTANCES = "nrOfCompletedInstances";
    protected String collectionElementIndexVariable = "loopCounter";

    private String parentExecutionId;

    private String activityId;

    private Map<String, Object> params;

    public AddMultiInstanceExecutionCmd(String parentExecutionId, String activityId, Map<String, Object> params) {
        this.parentExecutionId = parentExecutionId;
        this.activityId = activityId;
        this.params = params;
    }

    @Override
    public Void execute(CommandContext commandContext) {

        // 获取执行实例管理器
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();

        ExecutionEntity secondExecution = executionEntityManager.findById(parentExecutionId);
        if (secondExecution == null) {
            throw new RuntimeException("二级实例为空");
        }

        // 通过二级执行实例创建三级执行实例
        ExecutionEntity childExecution = executionEntityManager.createChildExecution(secondExecution);

        childExecution.setCurrentFlowElement(secondExecution.getCurrentFlowElement());

        BpmnModel model = ProcessDefinitionUtil.getBpmnModel(secondExecution.getProcessDefinitionId());
        Activity activity = (Activity) model.getFlowElement(secondExecution.getCurrentFlowElement().getId());

        MultiInstanceLoopCharacteristics loopCharacteristics = activity.getLoopCharacteristics();
        if (loopCharacteristics == null) {
            throw new RuntimeException("没有找到 MultiInstanceLoopCharacteristics");
        }
        if (!(activity.getBehavior() instanceof MultiInstanceActivityBehavior)) {
            throw new RuntimeException("这个节点不是多实例节点");
        }
        Integer currentNumberOfInstances = (Integer) secondExecution.getVariable(NUMBER_OF_INSTANCES);
        secondExecution.setVariableLocal(NUMBER_OF_INSTANCES, currentNumberOfInstances + 1);

        Integer currentNumberOfActiveInstances = (Integer) secondExecution.getVariable(NUMBER_OF_ACTIVE_INSTANCES);
        secondExecution.setVariableLocal(NUMBER_OF_ACTIVE_INSTANCES, currentNumberOfActiveInstances + 1);
        if (params != null) {
            childExecution.setVariables(params);
        }

        // 通知历史数据子实例开始运行
        HistoryManager historyManager = commandContext.getHistoryManager();
        historyManager.recordActivityStart(childExecution);

        // 触发行为类
        ParallelMultiInstanceBehavior behavior = (ParallelMultiInstanceBehavior) activity.getBehavior();

        behavior.getInnerActivityBehavior().execute(childExecution);


        return null;
    }

    protected Integer getLoopVariable(DelegateExecution execution, String variableName) {
        Object value = execution.getVariableLocal(variableName);
        DelegateExecution parent = execution.getParent();
        while (value == null && parent != null) {
            value = parent.getVariableLocal(variableName);
            parent = parent.getParent();
        }
        return (Integer) (value != null ? value : 0);
    }

}
